package tool

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"openmanus/llm"
)

// FileOperator 定义文件操作的接口
type FileOperator interface {
	ReadFile(path string) (string, error)
	WriteFile(path string, content string) error
	IsDirectory(path string) (bool, error)
	Exists(path string) (bool, error)
	RunCommand(cmd string, timeout float64) (int, string, string, error)
}

// LocalFileOperator 实现本地文件系统操作
type LocalFileOperator struct {
	encoding string
}

// NewLocalFileOperator 创建本地文件操作实例
func NewLocalFileOperator() *LocalFileOperator {
	return &LocalFileOperator{
		encoding: "utf-8",
	}
}

// ReadFile 读取本地文件内容
func (f *LocalFileOperator) ReadFile(path string) (string, error) {
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return "", fmt.Errorf("failed to read %s: %v", path, err)
	}
	return string(content), nil
}

// WriteFile 写入内容到本地文件
func (f *LocalFileOperator) WriteFile(path string, content string) error {
	// 确保目录存在
	dir := filepath.Dir(path)
	if dir != "" && dir != "." {
		if err := os.MkdirAll(dir, 0755); err != nil {
			return fmt.Errorf("failed to create directory: %v", err)
		}
	}

	err := ioutil.WriteFile(path, []byte(content), 0644)
	if err != nil {
		return fmt.Errorf("failed to write to %s: %v", path, err)
	}
	return nil
}

// IsDirectory 检查路径是否为目录
func (f *LocalFileOperator) IsDirectory(path string) (bool, error) {
	info, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, err
	}
	return info.IsDir(), nil
}

// Exists 检查路径是否存在
func (f *LocalFileOperator) Exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, err
	}
	return true, nil
}

// RunCommand 在本地运行shell命令
func (f *LocalFileOperator) RunCommand(cmd string, timeout float64) (int, string, string, error) {
	// 设置默认超时
	if timeout <= 0 {
		timeout = 120.0
	}

	// 根据操作系统选择shell
	var shell, flag string
	if runtime.GOOS == "windows" {
		shell = "cmd"
		flag = "/c"
	} else {
		shell = "/bin/sh"
		flag = "-c"
	}

	command := exec.Command(shell, flag, cmd)
	var stdout, stderr bytes.Buffer
	command.Stdout = &stdout
	command.Stderr = &stderr

	// 设置超时上下文
	timer := time.AfterFunc(time.Duration(timeout)*time.Second, func() {
		command.Process.Kill()
	})
	defer timer.Stop()

	err := command.Run()
	stdoutStr := stdout.String()
	stderrStr := stderr.String()

	// 处理超时情况
	if err != nil {
		if strings.Contains(err.Error(), "killed") {
			return -1, "", "", fmt.Errorf("command '%s' timed out after %v seconds", cmd, timeout)
		}
		// 尝试获取退出码
		if exitErr, ok := err.(*exec.ExitError); ok {
			return exitErr.ExitCode(), stdoutStr, stderrStr, err
		}
		return 1, stdoutStr, stderrStr, err
	}

	return 0, stdoutStr, stderrStr, nil
}

// SandboxFileOperator 实现沙箱环境的文件操作
type SandboxFileOperator struct {
	// 这里可以添加沙箱客户端引用
	// 在实际实现中需要连接到sandbox服务
}

// NewSandboxFileOperator 创建沙箱文件操作实例
func NewSandboxFileOperator() *SandboxFileOperator {
	return &SandboxFileOperator{}
}

// ensureSandboxInitialized 确保沙箱已初始化
func (s *SandboxFileOperator) ensureSandboxInitialized() error {
	// 在实际实现中，这里应该初始化沙箱连接
	// 目前返回未实现错误
	return errors.New("sandbox implementation not available")
}

// ReadFile 从沙箱中读取文件
func (s *SandboxFileOperator) ReadFile(path string) (string, error) {
	err := s.ensureSandboxInitialized()
	if err != nil {
		return "", fmt.Errorf("failed to read %s in sandbox: %v", path, err)
	}
	// 实际实现中需要调用沙箱API
	return "", fmt.Errorf("sandbox file read not implemented")
}

// WriteFile 写入内容到沙箱文件
func (s *SandboxFileOperator) WriteFile(path string, content string) error {
	err := s.ensureSandboxInitialized()
	if err != nil {
		return fmt.Errorf("failed to write to %s in sandbox: %v", path, err)
	}
	// 实际实现中需要调用沙箱API
	return fmt.Errorf("sandbox file write not implemented")
}

// IsDirectory 检查沙箱中路径是否为目录
func (s *SandboxFileOperator) IsDirectory(path string) (bool, error) {
	err := s.ensureSandboxInitialized()
	if err != nil {
		return false, err
	}
	// 实际实现中需要在沙箱中执行命令
	return false, fmt.Errorf("sandbox is_directory not implemented")
}

// Exists 检查沙箱中路径是否存在
func (s *SandboxFileOperator) Exists(path string) (bool, error) {
	err := s.ensureSandboxInitialized()
	if err != nil {
		return false, err
	}
	// 实际实现中需要在沙箱中执行命令
	return false, fmt.Errorf("sandbox exists not implemented")
}

// RunCommand 在沙箱环境中运行命令
func (s *SandboxFileOperator) RunCommand(cmd string, timeout float64) (int, string, string, error) {
	err := s.ensureSandboxInitialized()
	if err != nil {
		return 1, "", fmt.Sprintf("error executing command in sandbox: %v", err), nil
	}
	// 实际实现中需要调用沙箱API执行命令
	return 1, "", "sandbox run_command not implemented", nil
}

// FileOperatorsTool 提供文件操作工具
type FileOperatorsTool struct {
	ToolBase
	localOperator   *LocalFileOperator
	sandboxOperator *SandboxFileOperator
}

const fileOperatorsDescription = "Tool for file operations in local and sandbox environments."

// NewFileOperatorsTool 创建文件操作工具实例
func NewFileOperatorsTool() *FileOperatorsTool {
	tool := &FileOperatorsTool{
		localOperator:   NewLocalFileOperator(),
		sandboxOperator: NewSandboxFileOperator(),
	}

	tool.ToolBase = *NewToolBase("file_operators", fileOperatorsDescription, tool.buildParameters())

	return tool
}

// buildParameters 构建参数schema
func (f *FileOperatorsTool) buildParameters() llm.Schema {
	return llm.Schema{
		Type: "object",
		Properties: map[string]interface{}{
			"operation": map[string]interface{}{
				"type":        "string",
				"description": "The file operation to perform: read_file, write_file, is_directory, exists, run_command",
				"enum":        []string{"read_file", "write_file", "is_directory", "exists", "run_command"},
			},
			"path": map[string]interface{}{
				"type":        "string",
				"description": "The file or directory path for the operation",
			},
			"content": map[string]interface{}{
				"type":        "string",
				"description": "Content to write for write_file operation",
			},
			"command": map[string]interface{}{
				"type":        "string",
				"description": "Command to run for run_command operation",
			},
			"timeout": map[string]interface{}{
				"type":        "number",
				"description": "Timeout in seconds for command execution",
			},
			"environment": map[string]interface{}{
				"type":        "string",
				"description": "Execution environment: local or sandbox",
				"enum":        []string{"local", "sandbox"},
				"default":     "local",
			},
		},
		Required: []string{"operation"},
	}
}

// Execute 执行文件操作
func (f *FileOperatorsTool) Execute(params map[string]interface{}) (*ToolResult, error) {
	operation, ok := params["operation"].(string)
	if !ok || operation == "" {
		return FailResponse("Operation is required"), nil
	}

	environment := "local"
	if env, ok := params["environment"].(string); ok && env == "sandbox" {
		environment = "sandbox"
	}

	// 选择合适的文件操作器
	var operator FileOperator
	if environment == "sandbox" {
		operator = f.sandboxOperator
	} else {
		operator = f.localOperator
	}

	switch operation {
	case "read_file":
		return f.handleReadFile(params, operator)
	case "write_file":
		return f.handleWriteFile(params, operator)
	case "is_directory":
		return f.handleIsDirectory(params, operator)
	case "exists":
		return f.handleExists(params, operator)
	case "run_command":
		return f.handleRunCommand(params, operator)
	default:
		return FailResponse(fmt.Sprintf("Unknown operation: %s", operation)), nil
	}
}

// handleReadFile 处理文件读取操作
func (f *FileOperatorsTool) handleReadFile(params map[string]interface{}, operator FileOperator) (*ToolResult, error) {
	path, ok := params["path"].(string)
	if !ok || path == "" {
		return FailResponse("Path is required for read_file operation"), nil
	}

	content, err := operator.ReadFile(path)
	if err != nil {
		return FailResponse(fmt.Sprintf("Failed to read file: %v", err)), nil
	}

	return SuccessResponse(content), nil
}

// handleWriteFile 处理文件写入操作
func (f *FileOperatorsTool) handleWriteFile(params map[string]interface{}, operator FileOperator) (*ToolResult, error) {
	path, ok := params["path"].(string)
	if !ok || path == "" {
		return FailResponse("Path is required for write_file operation"), nil
	}

	content, ok := params["content"].(string)
	if !ok {
		content = ""
	}

	err := operator.WriteFile(path, content)
	if err != nil {
		return FailResponse(fmt.Sprintf("Failed to write file: %v", err)), nil
	}

	return SuccessResponse(fmt.Sprintf("Successfully wrote to %s", path)), nil
}

// handleIsDirectory 处理目录检查操作
func (f *FileOperatorsTool) handleIsDirectory(params map[string]interface{}, operator FileOperator) (*ToolResult, error) {
	path, ok := params["path"].(string)
	if !ok || path == "" {
		return FailResponse("Path is required for is_directory operation"), nil
	}

	isDir, err := operator.IsDirectory(path)
	if err != nil {
		return FailResponse(fmt.Sprintf("Failed to check if directory: %v", err)), nil
	}

	return SuccessResponse(map[string]interface{}{"is_directory": isDir}), nil
}

// handleExists 处理文件存在检查操作
func (f *FileOperatorsTool) handleExists(params map[string]interface{}, operator FileOperator) (*ToolResult, error) {
	path, ok := params["path"].(string)
	if !ok || path == "" {
		return FailResponse("Path is required for exists operation"), nil
	}

	exists, err := operator.Exists(path)
	if err != nil {
		return FailResponse(fmt.Sprintf("Failed to check if exists: %v", err)), nil
	}

	return SuccessResponse(map[string]interface{}{"exists": exists}), nil
}

// handleRunCommand 处理命令执行操作
func (f *FileOperatorsTool) handleRunCommand(params map[string]interface{}, operator FileOperator) (*ToolResult, error) {
	command, ok := params["command"].(string)
	if !ok || command == "" {
		return FailResponse("Command is required for run_command operation"), nil
	}

	timeout := 120.0
	if timeoutVal, ok := params["timeout"].(float64); ok && timeoutVal > 0 {
		timeout = timeoutVal
	}

	code, stdout, stderr, err := operator.RunCommand(command, timeout)
	result := map[string]interface{}{
		"return_code": code,
		"stdout":      stdout,
		"stderr":      stderr,
	}

	if err != nil {
		result["error"] = err.Error()
		return FailResponse(fmt.Sprintf("Command execution failed: %v", err)), nil
	}

	return SuccessResponse(result), nil
}
